<?php
///////////////////////////////////////////////////////////////////////////////////////////////////////
//  这个文件是 JCAT PHP框架的一部，该项目和此文件 均遵循 GNU 自由软件协议
// 
//  Copyleft 2008 JeCat.cn(http://team.JeCat.cn)
//
//
//  JCAT PHP框架 的正式全名是：Jellicle Cat PHP Framework。
//  “Jellicle Cat”出自 Andrew Lloyd Webber的音乐剧《猫》（《Prologue:Jellicle Songs for Jellicle Cats》）。
//  JCAT 是一个开源项目，它像音乐剧中的猫一样自由，你可以毫无顾忌地使用JCAT PHP框架。
//  JCAT 由中国团队开发维护，是一个国际性的项目。
//  正在使用的这个版本是：0.3.1 / SVN信息：$Id: class.JCAT_UIHtml.php 1119 2008-10-25 03:55:26Z alee $
//
//
//
//  相关的链接：
//    [主页] http://jcat.JeCat.cn
//    [HTTP下载] http://jcat.JeCat.cn/download
//    [在线文档] http://jcat.JeCat.cn/document
//    [社区] http://jj.jecat.cn/forum-7-1.html
//  不很相关：
//    [MP3] http://www.google.cn/search?q=jellicle+songs+for+jellicle+cats+Andrew+Lloyd+Webber
//    [VCD/DVD] http://www.google.cn/search?q=CAT+Andrew+Lloyd+Webber+video
//
///////////////////////////////////////////////////////////////////////////////////////////////////////
/*-- Project Introduce --*/




/**
 * HTML UI界面 模版类
 *
 * @author		alee
 * @access		public
 */
class JCAT_UIHtml extends JCAT_UI
{
	/**
	 * 
	 * @access	public
	 * @param	$aParserManager	JCAT_IUIObjectProcessorManager	处理器管理器
	 * @return	void
	 */
	public function JCAT_UIHtml( JCAT_IUIObjectProcessorManager $aParserManager=null ) 
	{
		$this->JCAT_UI($aParserManager) ;
		
		$this->aVariableSet = new _JCAT_UIHtmlVarSet() ;
	}
	
	/**
	 * 设置一个 分析器目录
	 * 
	 * @access	public
	 * @param	$sDir	string	分析器目录
	 * @static
	 * @return	void
	 */
	static public function AddParserDir( $sDir ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sDir) ;
		JCAT_ASSERT::ASSERT_DIR($sDir) ;
		
		$sDirPath = JCAT_Global::TidyPath($sDir) ;
		
		if( !in_array($sDirPath,self::$arrParserDirs) )
		{
			self::$arrParserDirs[] = $sDirPath ;
		}
	}



	/**
	 * 清空已设置的分析器目录，并返回原有的数量
	 * 
	 * @access	public
	 * @static
	 * @return	int
	 */
	static public function ClearParserDir(  ) 
	{
		$nCount = count(self::$arrParserDirs) ;
		self::$arrParserDirs = array() ;
		return $nCount ;
	}



	/**
	 * 创建一个默认的 分析器管理器
	 * 
	 * @access	public
	 * @static
	 * @return	JCAT_UIObjectProcessorManager
	 */
	static public function GetDefaultParserManager(  ) 
	{
		$aParserManager = new JCAT_UIObjectProcessorManager() ;
		
		// 加入 Code 和 Node 分析器
		JCAT_UIHtmlCodeParser::RegistorToProcessorManager($aParserManager) ;
		JCAT_UIHtmlCodeSimpleParser::RegistorToProcessorManager($aParserManager) ;
		JCAT_UIHtmlNodeParser::RegistorToProcessorManager($aParserManager) ;
		JCAT_UIHtmlRevertParser::RegistorToProcessorManager($aParserManager) ;
		
		// 自动加入其他编译器
		foreach(self::$arrParserDirs as $sDirPath)
		{
			$aParserManager->AutoloadProcessor($sDirPath) ;
		}
		
		return $aParserManager ;
	}

	/**
	 * 创建一个全局的 默认模板目录管理器
	 * 
	 * @access	public
	 * @static
	 * @return	void
	 */
	static public function CreateDefaultTemplateDirManger(  )
	{
		self::$aUITemplateFileManager = new JCAT_UITemplateFileManager() ;
	}

	/**
	 * 设置一个模版文件存放目录
	 * 
	 * @access	public
	 * @param	$sDir	string	模版文件存放目录
	 * @static
	 * @return	void
	 */
	static public function AddTemplateDir($sDir) 
	{
		return self::$aUITemplateFileManager->AddTemplateDir($sDir) ;
	}



	/**
	 * 清空已经设置的模版文件目录
	 * 
	 * @access	public
	 * @static
	 * @return	int
	 */
	static public function ClearTemplateDirs() 
	{
		return self::$aUITemplateFileManager->ClearTemplateDirs() ;
	}



	/**
	 * 创建一个 模版目录  的备忘录
	 * 
	 * @access	public
	 * @static
	 * @return	array
	 */
	static public function CreateTemplateDirsMemento() 
	{ return self::$aUITemplateFileManager->CreateTemplateDirsMemento() ; }



	/**
	 * 使用 一个备忘录
	 * 
	 * @access	public
	 * @param	$arrMemento	array	备忘录
	 * @static
	 * @return	old_var
	 */
	static public function SetTemplateDirsMemento( array $arrMemento )
	{ return self::$aUITemplateFileManager->SetTemplateDirsMemento($arrMemento) ; }


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @static
	 * @return	JCAT_ArrayReverseIterator
	 */
	static public function CreateTemplateDirIterator()
	{ return self::$aUITemplateFileManager->CreateTemplateDirIterator() ; }

	/**
	 * 根据模版 文件名查找 文件
	 * 
	 * @access	public
	 * @param	$sTemplateFile					string	模版文件名称
	 * @static
	 * @return	string
	 */
	static public function FindTemplate( $sTemplateFile )
	{ return self::$aUITemplateFileManager->FindTemplate($sTemplateFile) ; }

	/**
	 * 加入一个UI对象
	 * 
	 * @access	public
	 * @param	$aUIObject	JCAT_UIObject	UI对象
	 * @return	void
	 */
	public function PutInUIObject( JCAT_UIObject $aUIObject ) 
	{
		// 顶级对象
		$aIterator = $this->CreateUIObjectIterator() ;
		$aTopUIObject = $aIterator->First() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aTopUIObject,'JCAT_UIHtmlObject') ;
		
		// 插入
		$aTopUIObject->AddUIObject($aUIObject) ;
	}
	
	
	/**
	 * 分析模版前处理
	 * 
	 * @access	public
	 * @param	$sParseSource		string	分析原文
	 * @return	void
	 */
	protected function BeforeParse( & $sParseSource ) 
	{		
		// 创建顶级UIObject
		$aTopUIObject = new JCAT_UIHtmlObject($sParseSource) ;
		$aTopUIObject->Locate($sParseSource,0) ;
		
		$this->ClearUIObject() ;
		JCAT_UI::PutInUIObject($aTopUIObject) ;
	}

	/**
	 * 显示模版
	 * 
	 * @access	public
	 * @param	$sTemplateFile					string	模版文件的路径 或 名称
	 * @param	$bDisplayAtOnce=true 			bool	是否立即显示
	 * @param	$nVarFlags=self::VAR_DEFAULT	int		变量规则
	 * @return	string
	 */
	public function Display( $sTemplateFile, $bDisplayAtOnce=true, $nVarFlags=self::VAR_DEFAULT ) 
	{
		JCAT_ASSERT::ASSERT_STRING($sTemplateFile) ;
		JCAT_ASSERT::ASSERT_BOOL($bDisplayAtOnce) ;
		JCAT_ASSERT::ASSERT_INT($nVarFlags) ;
		
		if( is_file($sTemplateFile) )
		{
			$sTemplatePath =& $sTemplateFile ;
		}
		else
		{
			$sTemplatePath = self::FindTemplate(&$sTemplateFile) ;
		}
		
		JCAT_ASSERT::ASSERT_FILE($sTemplatePath,JCAT_Language::SentenceEx('无法找到模板文件：“%s”','JCAT',null,$sTemplateFile))  ;
		
		// 需要的变量 引用至此 -------
		if( $nVarFlags!==self::VAR_NONE )
		{
			$arrHideVariables = array() ;
			$nExtractFlag = EXTR_PREFIX_SAME|(($nVarFlags&self::VAR_AS_REF)?EXTR_REFS:0) ;
			
			// 通过 SetVar 和 SetVars 设置的 变量
			if( $nVarFlags&self::VAR_SETED )					
			{
				$arrVars =& $this->aVariableSet->GetVarsArray() ;
				if( is_array($arrVars) and count($arrVars) )
				{
					extract($arrVars, $nExtractFlag, 'ui_') ;
				}
			}
			
			// 一些内建的全局变量
			$arrBuildinGlobalVariable = array(
				'_GET' => self::VAR_GET ,
				'_POST' => self::VAR_POST ,
				'_COOKIE' => self::VAR_COOKIE ,
				'_SERVER' => self::VAR_SERVER ,
				'_FILES' => self::VAR_FILES ,
			) ;
			foreach($arrBuildinGlobalVariable as $sVarName=>$nFlag)
			{
				if( !($nVarFlags&$nFlag) )
				{
					$arrHideVariables[$sVarName] =& $$sVarName ;
					unset($$sVarName) ;
				}
			}
			
			// 自定义的 全局变量
			if( $nVarFlags&self::VAR_GLOBAL )
			{
				$arrGlobalVars = array() ;
				foreach ($GLOBALS as $key=>&$item)
				{
					if( !in_array($key,array('GLOBALS','_ENV','HTTP_ENV_VARS','_POST','HTTP_POST_VARS','_GET','HTTP_GET_VARS','_COOKIE','HTTP_COOKIE_VARS','_SERVER','HTTP_SERVER_VARS','_FILES','HTTP_POST_FILES','_REQUEST')) )
					{
						$arrGlobalVars[$key] =& $item ;
					}
				}
				extract($arrGlobalVars,$nExtractFlag,'ui_') ;
			}
		
		}
		
		// 编译文件路径
		$sCompiledPath = $this->GetCompiledPath($sTemplatePath) ;
		
		// 重新编译
		if( $this->IsCompiledFileExpired($sTemplatePath,$sCompiledPath) )
		{
			$this->Compile($sTemplatePath,$sCompiledPath) ;
		}
		
		// 拦截输出
		$this->StartHoldupDisplayBuffer($bDisplayAtOnce) ;

		// 载入 编译文件
		include $sCompiledPath ;
		
		// 返回
		$sReturn =& $this->EndHoldupDisplayBuffer() ; // echo '---' ;
		return $sReturn ;
	}



	/**
	 * 从缓存中显示一个模版
	 * 
	 * @access	public
	 * @param	$sTemplateFile					string	模版文件的路径 或 名称
	 * @param	$sCacheName						string	缓存名称
	 * @param	$nTime=0						int		缓存时间
	 * @param	$bDisplayAtOnce=true 			bool	是否立即显示
	 * @param	$nVarFlags=self::VAR_DEFAULT	int		变量规则
	 * @return	void
	 */
	public function DisplayCache( $sTemplateFile, $sCacheName, $nTime=0, $bDisplayAtOnce=true, $nVarFlags=self::VAR_DEFAULT ) 
	{
		$aCache = $this->GetCache() ;
		JCAT_ASSERT::ASSERT_INSTANCE($aCache,JCAT_Language::SentenceEx('尚未设置缓存器，通过 CreateHDCache() 或 SetCache() 设置。','JCAT',null)) ;
		
		$sCache = '' ;
		
		// 未过期
		if( !$aCache->IsExpired($sCacheName,$nTime) )
			$sCache = $aCache->Get($sCacheName) ;

		// 已过期
		else
			$sCache = $this->DisplayCache($sTemplateFile,false,$nVarFlags) ;
		
		// 立即输出
		if($bDisplayAtOnce)
			print $sCache ;
		
		// 返回
		return $sCache ;
	}


	

	/**
	 * 通过缓存目录，创建一个 硬盘文件缓存器
	 * 
	 * @access	public
	 * @param	$sCacheDir		JCAT_ICache	What's this Parameter ?
	 * @return	JCAT_HDCache
	 */
	public function CreateHDCache( $sCacheDir ) 
	{
		JCAT_ASSERT::ASSERT_DIR($aCache,'sCacheDir') ;
		return $this->aCache = new JCAT_HDCache($sCacheDir) ;
	}

	/**
	 * 设置一个缓存器
	 * 
	 * @access	public
	 * @param	$aCache		JCAT_ICache		缓存器
	 * @return	old_var
	 */
	public function SetCache( $aCache ) 
	{
		JCAT_ASSERT::ASSERT_INSTANCE($aCache,'JCAT_ICache') ;
		
		$old_value = $this->aCache ;
		$this->aCache = $aCache ;
		return $old_value ;
	}



	/**
	 * 返回当前的缓存器
	 * 
	 * @access	public
	 * @return	JCAT_ICache, null
	 */
	public function GetCache() 
	{ return $this->aCache ; }



	/**
	 * 设置用户界面变量
	 * 
	 * @access	public
	 * @param	$NameOrVars		array,string		变量名称 或 包含所有变量的数组
	 * @param	$Value				mixed			变量值
	 * @return	old_var,null
	 */
	public function SetVar( $NameOrVars, $Value=null ) 
	{
		if( is_string($NameOrVars) )
		{
			return $this->aVariableSet->SetVar(&$NameOrVars, &$Value) ;
		}
			
		elseif( is_array($NameOrVars) )
		{
			foreach($NameOrVars as $sName=>&$EachValue)
			{
				$this->aVariableSet->SetVar(&$sName, &$EachValue) ;
			}
		}
		
		else
		{
			JCAT_ASSERT::ASSERT_(0,JCAT_Language::SentenceEx('参数 $NameOrVars 必须为数组或字符串','JCAT',null)) ;
		}
	}


	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$sName	string	What's this Parameter ?
	 * @return	mixed
	 */
	public function GetVar( $sName ) 
	{
		return $this->aVariableSet->Get(&$sName) ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @return	_JCAT_UIHtmlVarSet
	 */
	public function CreateVarSetMemento() 
	{
		return clone $this->aVariableSet ;
	}



	/**
	 * What's this Method ?
	 * 
	 * @access	public
	 * @param	$aMemento	_JCAT_UIHtmlVarSet	What's this Parameter ?
	 * @return	old_value
	 */
	public function SetVarSetMemento(  $aMemento ) 
	{
		JCAT_ASSERT::ASSERT_INSTANCE($aMemento,'_JCAT_UIHtmlVarSet') ;
		
		$old_value = $this->aVariableSet ;
		$this->aVariableSet = $aMemento ;
		return $old_value ;
	}


	/**
	 * 
	 *
	 * @access	public
	 * @param	$		What's this Parameter ?
	 * @return	void
	 */
	public function HoldupDisplay(&$sBuffer)
	{
		$this->sDisplayBuffer.= $sBuffer ;
		
		if(!$this->bHoldupDisplayBuffer)
			return $sBuffer ;
	}
	
	
	/**
	 * 
	 *
	 * @access	public
	 * @param	$bDisplayAtOnce=true 			bool	是否立即显示
	 * @return	void
	 */
	private function StartHoldupDisplayBuffer($bDisplayAtOnce)
	{
		$this->sDisplayBuffer = '' ;
		$this->bHoldupDisplayBuffer = !$bDisplayAtOnce ;
		ob_start( array($this,'HoldupDisplay') ) ;
	}
	
	/**
	 * 
	 *
	 * @access	public
	 * @return	void
	 */
	private function EndHoldupDisplayBuffer()
	{
		ob_end_flush() ;
		return $this->sDisplayBuffer ;
	}
	

	// 属性 ///////////////////////////////////////////////////////////////////////////////

	/**
	 * 缺省的全局模板目录管理器
	 * 
	 * @access	private
	 * @static
	 * @var		JCAT_UITemplateFileManager
	 */
	static private $aUITemplateFileManager ;

	/**
	 * 分析器目录
	 * 
	 * @access	private
	 * @var		array:string
	 */
	static private $arrParserDirs = array() ;


	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_NONE = 0 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_AS_REF = 1 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_GET = 2 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_POST = 4 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_COOKIE = 8 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_SERVER = 16 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_FILES = 32 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_GLOBAL = 64 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_SETED = 128 ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_REQUEST = 14 ;//VAR_GET|VAR_POST|VAR_COOKIE ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_DEFAULT = 143 ;//VAR_AS_REF|VAR_REQUEST|VAR_SETED ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	const
	 * @var		int
	 */
	const VAR_ALL = 255 ;//VAR_DEFAULT|VAR_SERVER| VAR_FILES|VAR_GLOBAL ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		
	 */
	private $aVariableSet ;

	/**
	 * What's this Attribute ?
	 * 
	 * @access	private
	 * @var		
	 */
	private $aCache = null ;
	
	
	private $sDisplayBuffer ;
	
	
	private $bHoldupDisplayBuffer ;


}


// 创建缺省的 模板目录管理器
JCAT_UIHtml::CreateDefaultTemplateDirManger() ;



?>
